﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Collections;

namespace K_Means
{
	public struct AttributeDetails
	{
		public bool Type;
		public Dictionary<string, int> Labels;
		public double Minimum;
		public double Maximum;
		public double Mean;
		public int Missing;
		public List<double> Rows;
		public double StandardDeviation;
	}
	public class Preprocess
	{
		private string[] _attributes;
		private List<string[]> _properties;
		private AttributeDetails[] _attributeDetails;
		public string[] Attributes
		{
			get
			{
				return this._attributes;
			}
		}

		public List<string[]> Properties
		{
			get
			{
				return this._properties;
			}
		}

		public AttributeDetails[] AttributeDetails
		{
			get
			{
				return this._attributeDetails;
			}
		}
		public Preprocess(string _name)
		{
			try
			{
				this._properties = new List<string[]>();
				using (StreamReader sr = new StreamReader(_name))
				{
					if (sr.Peek() >= 0)
					{
						this._attributes = sr.ReadLine().Split(',');
						this._attributeDetails = new AttributeDetails[this._attributes.Length];
						for (int i = 0; i < this._attributes.Length; i++)
						{
							this._attributeDetails[i] = new AttributeDetails();
							this._attributeDetails[i].Type = false;
							this._attributeDetails[i].Labels = new Dictionary<string, int>();
							this._attributeDetails[i].Minimum = double.MaxValue;
							this._attributeDetails[i].Maximum = 0.0;
							this._attributeDetails[i].Mean = 0.0;
							this._attributeDetails[i].Missing = 0;
						}
					}
					#region
					while (sr.Peek() >= 0)
					{
						string[] properties = sr.ReadLine().Split(',');
						for (int i = 0; i < properties.Length; i++)
						{
							if (properties[i] == "" || properties[i] == "?") {
								this._attributeDetails[i].Missing++;
								break;
							}
							try
							{
								
								if (!this._attributeDetails[i].Labels.ContainsKey(properties[i]))
								{
									this._attributeDetails[i].Labels.Add(properties[i], 1);
								}
								else
								{
									this._attributeDetails[i].Labels[properties[i]]++;
								}
								if (!this._attributeDetails[i].Type)
								{
									double property = double.Parse(properties[i]);
									this._attributeDetails[i].Minimum = (property < this._attributeDetails[i].Minimum) ? property : this._attributeDetails[i].Minimum;
									this._attributeDetails[i].Maximum = (property > this._attributeDetails[i].Maximum) ? property : this._attributeDetails[i].Maximum;
									this._attributeDetails[i].Mean += property;
								}
								else
								{
									this._attributeDetails[i].Type = true;
								}
							}
							catch (System.FormatException)
							{
								this._attributeDetails[i].Type = true;
							}
							
						}
						this._properties.Add(properties);
					}
					#endregion
				}
				for (int i = 0; i < this._attributes.Length; i++)
				{
					if (!this._attributeDetails[i].Type)
					{
						this._attributeDetails[i].Mean /= (this._properties.Count - this._attributeDetails[i].Missing);
					}
				}

				#region
				for (int i = 0; i < this._attributeDetails.Length; i++)
				{
					double mean = 0.0;
					this._attributeDetails[i].Rows = new List<double>(this._properties.Count);
					if (this._attributeDetails[i].Type)
					{
						this._attributeDetails[i].Minimum = 0;
						this._attributeDetails[i].Maximum = this._attributeDetails[i].Labels.Count - 1;
						for (int j = 0; j < this._properties.Count; j++)
						{
							Dictionary<string, int> indexs = new Dictionary<string, int>();
							int k = 0;
							foreach (string key in this._attributeDetails[i].Labels.Keys)
							{
								indexs.Add(key, k);
								k++;
							}
							mean += indexs[this._properties[j][i]];
							this._attributeDetails[i].Rows.Add(indexs[this._properties[j][i]]);
						}
						this._attributeDetails[i].Mean = mean / this._attributeDetails[i].Rows.Count;
					}
					else
					{
						for (int j = 0; j < this._properties.Count; j++)
						{
							this._attributeDetails[i].Rows.Add((this._properties[j][i] == "" || this._properties[j][i] == "?") ? this._attributeDetails[i].Mean : double.Parse(this._properties[j][i]));
						}
					}
					double stddev = 0.0;
					mean = this._attributeDetails[i].Mean;
					for (int j = 0; j < this._attributeDetails[i].Rows.Count; j++)
					{
						stddev += (this._attributeDetails[i].Rows[j] - mean) * (this._attributeDetails[i].Rows[j] - mean);
					}
					this._attributeDetails[i].StandardDeviation = Math.Sqrt(stddev / this._attributeDetails[i].Rows.Count);
				}
				#endregion

				#region
				for (int i = 0; i < this._attributeDetails.Length; i++)
				{
					double tmp = this._attributeDetails[i].Maximum - this._attributeDetails[i].Minimum;
					for (int j = 0; j < this._attributeDetails[i].Rows.Count; j++)
					{
						if (tmp != 0)
						{
							this._attributeDetails[i].Rows[j] = (this._attributeDetails[i].Rows[j] - this._attributeDetails[i].Minimum) / tmp;
						}
					}
				}
				#endregion
			}
			catch (System.IO.IOException ex)
			{
				System.Windows.Forms.MessageBox.Show(ex.ToString());
			}
			catch (System.OutOfMemoryException ex)
			{
				System.Windows.Forms.MessageBox.Show(ex.ToString());
			}
			catch (System.Exception ex)
			{
				System.Windows.Forms.MessageBox.Show(ex.Message);
			}
		}
	}
}
